/********************************************************************
* Name: X86Code.h: 
*
* Description:
*   Abstract structure type of x86 binary.
*   Facilitate optimization, etc.
*
* History:
*   Create: gxf. 2008-11-15
*   Rev. 1: gxf. 2009-03-28 Interface division. 
*
********************************************************************/

#ifndef X86_CODE_H
#define X86_CODE_H

#include "crossbit/common.h"
#include <list>
#include <string>
#include <iostream>
#include <cassert>

namespace crossbit{

namespace x86code{

// enum all x86 opcode types
enum X86OpCode{
#define OP(opCode)  X86_OP_##opCode
    // x86
    // Data move
    OP(MOV), OP(MOVI), OP(MOVIR), OP(MOVZX16), OP(LEA), 
                
    // Arithmetic
    OP(ADD), OP(SUB), OP(OR), OP(XOR), OP(AND), 
    OP(SBB), OP(NEG), OP(NOT), OP(CMP), OP(TEST),
    OP(SHL), OP(SHR), OP(SAL), OP(SAR),
    OP(SHL_CL), OP(SHR_CL), OP(SAL_CL), OP(SAR_CL),

    // Control Transfer 
    OP(CALL), OP(RET), 
    OP(PUSH), OP(POP),
    OP(JCC),
    OP(CMOV),
    OP(SETCC),
    OP(MUL),         // unsigned mul by EAX
    OP(TESTI),
    OP(IMUL),        // flexible IMUL
    OP(IMULI),       // Flexible signed mul by immediate
    OP(ANDI), OP(ORI), OP(XORI),
    OP(ADDI), OP(SUBI), OP(INC), OP(DEC),
    OP(CMPI),
    OP(CALLI), OP(RETI), OP(JMP_REL),
    OP(NOP),         // pads out to the specified alignment
    OP(RDTSC),
    OP(MFENCE),
    OP(DIV),

    // SSE Instructions
    // Vector
    OP(ADDPS), OP(SUBPS), OP(MULPS), OP(DIVPS),
    OP(MAXPS), OP(MINPS),
    OP(SHUFPS),
    OP(RSQRTPS),
    OP(RCPPS),
    OP(ANDPS), OP(ANDNPS),
    OP(ORPS),  OP(XORPS),
    OP(MOVPS),       // May become MOVAPS), MOVUPS
    OP(MOVAPS), OP(MOVUPS), OP(MOVNTPS),
    OP(CMPPS),
    OP(MOVLPS), OP(MOVHPS),
    OP(CVTPI2PS), OP(CVTPS2PI), OP(CVTSI2SS), OP(CVTTPS2PI),
    OP(MOVHLPS), OP(MOVLHPS),
    OP(UNPCKHPS), OP(UNPCKLPS),
    OP(MOVMSKPS), 
            
    // SSE Scalar
    OP(ADDSS), OP(SUBSS), OP(MULSS), OP(DIVSS),
    OP(MOVSS),
    OP(CMPSS),

    // SSE Control
    OP(STMXCSR), OP(LDMXCSR), OP(FXSAVE),
    // Guard token
    OP(NONE),
#undef OP
};

// enum all x86 registers
enum X86Reg{ 
    REG_NONE    = 0x00000000;
    // GP regs 
    REG_EAX     = 0x00000001;
    REG_EBX     = 0x00000002;
    REG_ECX     = 0x00000004;
    REG_EDX     = 0x00000008;
    REG_ESP     = 0x00000010;
    REG_EBP     = 0x00000020;
    REG_ESI     = 0x00000040;
    REG_EDI     = 0x00000080;
    // SSE regs 
    REG_XMM0    = 0x00010000;
    REG_XMM1    = 0x00020000;
    REG_XMM2    = 0x00040000;
    REG_XMM3    = 0x00080000;
    REG_XMM4    = 0x00100000;
    REG_XMM5    = 0x00200000;
    REG_XMM6    = 0x00400000;
    REG_XMM7    = 0x00800000;
    // Mask
    REG_MASK_GP = 0x0000ffff;
    REG_MASK_SSE= 0xffff0000;
};
        
enum X86OprndType{
    TP_NONE,
    TP_REG,
    TP_IMM,
    TP_ADDR,
};

/*
enum X86CondCode{
    EQ, NE, NA, GT, GE, LT, LE, AB, BE,
};
*/

class X86Oprnd{
    public:
        union {
            XTUInt32 immd;
            X86Reg   reg;
            XTUInt32 addr;
        };
        X86OprndType type;

    public:
        X86Oprnd():
            reg(REG_NONE), type(TP_NONE)
        {}
};

class X86Code{
#define MAX_OPRAND 5
    public:
        X86OpCode   opcode;
        X86Oprnd    oprnd[MAX_OPRAND];
        XTUInt32    num_oprnd;

    public:
        X86Code(X86OpCode opcd = X86_OP_NONE):
            opcode(opcd), num_oprnd(0)
        {}
};

// Define x86 instructions structure, mainly used for optimization
class X86Inst{
    public:
        X86Opcode   op_code;
        XTCPStr     op_name;

    public:
        // For optimization
        X86Reg      reg_imp_use;    // Reg that the inst implicit use 
        X86Reg      reg_imp_chg; // Reg that the inst implicit change

    public:
        // This table records all x86 insts in structure;
        const static X86Inst InstTable[]=
        {
            // TODO: hard work...
            {X86_OP_MOV, "mov", REG_NONE, REG_NONE},
            {X86_OP_MOVI, "movi", REG_NONE, REG_NONE},
            {X86_OP_MOVIR, "movir", REG_NONE, REG_NONE},
            {X86_OP_MOVZX16, "movzx16", REG_NONE, REG_NONE},
            {X86_OP_LEA, "lea", REG_NONE, REG_NONE},
            {X86_OP_ADD, "add", REG_NONE, REG_NONE},
            {X86_OP_SUB, "sub", REG_NONE, REG_NONE},
            {X86_OP_OR, "or", REG_NONE, REG_NONE},
            {X86_OP_XOR, "xor", REG_NONE, REG_NONE},
            {X86_OP_AND, "add", REG_NONE, REG_NONE},
            {X86_OP_SBB, "sbb", REG_NONE, REG_NONE},
            {X86_OP_NEG, "neg", REG_NONE, REG_NONE},
            {X86_OP_NOT, "not", REG_NONE, REG_NONE},
            {X86_OP_CMP, "cmp", REG_NONE, REG_NONE},
            {X86_OP_TEST, "test", REG_NONE, REG_NONE},
            {X86_OP_SHL, "shl", REG_NONE, REG_NONE},
            {X86_OP_SHR, "shr", REG_NONE, REG_NONE},
            {X86_OP_SAL, "sal", REG_NONE, REG_NONE},
            {X86_OP_SAR, "sar", REG_NONE, REG_NONE},
            {X86_OP_SHL_CL, "shl_cl", REG_NONE, REG_NONE},
            {X86_OP_SHR_CL, "shr_cl", REG_NONE, REG_NONE},
            {X86_OP_SAL_CL, "sal_cl", REG_NONE, REG_NONE},
            {X86_OP_SAR_CL, "sar_cl", REG_NONE, REG_NONE},
            {X86_OP_CALL, "call", REG_NONE, REG_NONE},
            {X86_OP_RET, "ret", REG_NONE, REG_NONE},
            {X86_OP_PUSH, "push", REG_NONE, REG_NONE},
            {X86_OP_POP, "pop", REG_NONE, REG_NONE},
            {X86_OP_JCC, "jcc", REG_NONE, REG_NONE},
            {X86_OP_CMOV, "cmov", REG_NONE, REG_NONE},
            {X86_OP_SETCC, "setcc", REG_NONE, REG_NONE},
            {X86_OP_MUL, "mul", REG_NONE, REG_NONE},
            {X86_OP_TESTI, "testi", REG_NONE, REG_NONE},
            {X86_OP_IMUL, "imul", REG_NONE, REG_NONE},
            {X86_OP_IMULI, "imuli", REG_NONE, REG_NONE},
            {X86_OP_ANDI, "andi", REG_NONE, REG_NONE},
            {X86_OP_ORI, "ori", REG_NONE, REG_NONE},
            {X86_OP_XORI, "xori", REG_NONE, REG_NONE},
            {X86_OP_ADDI, "addi", REG_NONE, REG_NONE},
            {X86_OP_SUBI, "subi", REG_NONE, REG_NONE},
            {X86_OP_INC, "inc", REG_NONE, REG_NONE},
            {X86_OP_DEC, "dec", REG_NONE, REG_NONE},
            {X86_OP_CMPI, "cmpi", REG_NONE, REG_NONE},
            {X86_OP_CALLI, "calli", REG_NONE, REG_NONE},
            {X86_OP_RETI, "reti", REG_NONE, REG_NONE},
            {X86_OP_JMP_REL, "jmp_rel", REG_NONE, REG_NONE},
            {X86_OP_NOP, "nop", REG_NONE, REG_NONE},
            {X86_OP_RDTSC, "rdtsc", REG_NONE, REG_NONE},
            {X86_OP_ADDPS, "addps", REG_NONE, REG_NONE},
            {X86_OP_SUBPS, "subps", REG_NONE, REG_NONE},
            {X86_OP_MULPS, "mulps", REG_NONE, REG_NONE},
            {X86_OP_DIVPS, "divps", REG_NONE, REG_NONE},
            {X86_OP_MAXPS, "maxps", REG_NONE, REG_NONE},
            {X86_OP_MINPS, "minps", REG_NONE, REG_NONE},
            {X86_OP_SHUFPS, "shufps", REG_NONE, REG_NONE},
            {X86_OP_RSQRTPS, "rsqrtps", REG_NONE, REG_NONE},
            {X86_OP_RCPPS, "rcpps", REG_NONE, REG_NONE},
            {X86_OP_ANDPS, "andps", REG_NONE, REG_NONE},
            {X86_OP_ANDNPS, "andnps", REG_NONE, REG_NONE},
            {X86_OP_ORPS, "orps", REG_NONE, REG_NONE},
            {X86_OP_XORPS, "xorps", REG_NONE, REG_NONE},
            {X86_OP_MOVAPS, "movaps", REG_NONE, REG_NONE},
            {X86_OP_MOVUPS, "movups", REG_NONE, REG_NONE},
            {X86_OP_MOVNTPS, "movntps", REG_NONE, REG_NONE},
            {X86_OP_CMPPS, "cmpps", REG_NONE, REG_NONE},
            {X86_OP_MOVLPS, "movlps", REG_NONE, REG_NONE},
            {X86_OP_MOVHPS, "movhps", REG_NONE, REG_NONE},
            {X86_OP_UNPCKHPS, "unpckhps", REG_NONE, REG_NONE},
            {X86_OP_UNPCKLPS, "unpcklps", REG_NONE, REG_NONE},
            {X86_OP_MOVMSKPS, "movmskps", REG_NONE, REG_NONE},
            {X86_OP_ADDSS, "addss", REG_NONE, REG_NONE},
            {X86_OP_SUBSS, "subss", REG_NONE, REG_NONE},
            {X86_OP_MULSS, "mulss", REG_NONE, REG_NONE},
            {X86_OP_DIVSS, "divss", REG_NONE, REG_NONE},
            {X86_OP_MOVSS, "movss", REG_NONE, REG_NONE},
            {X86_OP_CMPSS, "cmpss", REG_NONE, REG_NONE},
            {X86_OP_STMXCSR, "stmxcsr", REG_NONE, REG_NONE},
            {X86_OP_LDMXCSR, "ldmxcsr", REG_NONE, REG_NONE},
            {X86_OP_FXSAVE, "fxsave", REG_NONE, REG_NONE},
        };
}; // class X86Inst

} // namespace x86code

} // namespace crossbit

#endif
